"""
哔哩哔哩视频解析器
"""
import json
import re

from btools import FileTools, UrlTools, Logger, bsubprocess
from threading import Thread
import requests
from PySide2.QtCore import QObject, Signal


class Mysignals(QObject):
    """
    自定义信号源
    """

    def __init__(self):
        super(Mysignals, self).__init__()

    resolution_success = Signal(list)
    log_append = Signal(str)


# 自定义抓取logging日志到ui的类

class Bilibili:
    """
    哔哩哔哩解析器类
    """

    def __init__(self, url, ui):
        self.fts = FileTools()
        self.url = url
        self.logger = Logger()
        self.logger.setlever('DEBUG')
        self.ui = ui
        # loghandle = LogHandler(self.logtoui, self.ui.textbrower_log)
        # self.logger.logger.addHandler(hdlr=loghandle)
        self.uts = UrlTools()
        # 自定义信号
        self.ms = Mysignals()
        self.ms.resolution_success.connect(self.update_resolution_ui)
        self.ms.log_append.connect(self.log_append)
        self.ui.combobox_resolution.currentTextChanged.connect(self.change_resolution)
        self.format_data_dict = None
        self.request_t = None
        self.urls = {}
        self.video_data = None
        self.video_title = ''
        self.audio = True
        # 当前项目的根路径(btools.py的路径)
        self.workpath = self.fts.getworkdir()
        self.fts.chdir(self.workpath)
        self.headers = {
            'user-agent': r'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36',
            'referer': r'https://www.bilibili.com/'
        }
        self.video_local_path = ''
        self.audio_local_path = ''
        # 下载路径
        self.fd = ''

    def analysis(self):
        """
        处理点击解析按钮事件的句柄
        """
        sourcedata = self.craw()
        self.analysis_handel(sourcedata)

    def craw(self):
        """
        爬取网页源代码
        """
        res = requests.get(self.url, headers=self.headers)
        if res.status_code == 200:
            return res
        else:
            self.logger.error('请求网页源代码失败')

    def analysis_handel(self, sourcedata):
        """
        解析源代码,获取url
        """
        self.ui.textbrower_log.setText('')
        self.logger.info('开始解析...')
        self.ms.log_append.emit('开始解析...')

        # 获取视频数据的正则
        pattern = r'window.__playinfo__=(.*)</script><script>window.__INITIAL_STATE__='
        # 获取视频标题的正则
        pattern2 = r'<title data-vue-meta="true">(.*)</title>'
        self.video_data = json.loads(re.findall(pattern, sourcedata.text.strip())[0]).get('data')
        self.video_title = re.findall(pattern2, sourcedata.text.strip())[0]
        self.logger.debug(f'视频标题:{self.video_title}')
        if self.video_data:
            support_formats = self.video_data.get('support_formats')
            self.ms.resolution_success.emit(support_formats)
        else:
            self.logger.error('没有获取到视频数据')
            self.ms.log_append.emit('没有获取到视频数据')
            self.ui.button_analysis.setEnabled(False)

    def download(self, fd):
        """
        处理点击下载按钮的事件
        """

        # 创建对应标题的文件夹
        self.logger.info('开始下载...')
        self.ms.log_append.emit('开始下载...')
        self.logger.debug(self.urls)
        ts = []
        self.fd = fd
        for filetype, url in self.urls.items():
            t = Thread(target=self.download_file, args=(filetype, url))
            ts.append(t)
        for t in ts:
            t.start()
            t.join()
        else:
            # pass
            self.merge()

    def download_file(self, filetype, url):
        """
        下载文件写入到本地
        """
        if filetype == 'video':
            r = requests.get(url, headers=self.headers)
            self.video_local_path = self.fts.join(self.fd, 'old_video.mp4')
            with open(self.video_local_path, 'wb') as stream:
                stream.write(r.content)
                # self.ms.log_append.emit(f'视频地址是:{self.video_local_path}')
        if filetype == 'audio':
            r = requests.get(url, headers=self.headers)
            self.audio_local_path = self.fts.join(self.fd, 'audio.mp3')
            with open(self.audio_local_path, 'wb') as stream:
                stream.write(r.content)
                # self.ms.log_append.emit(f'音频地址是:{self.audio_local_path}')

    def merge(self):
        """
        合并所有下载的文件成mp4
        """
        self.ms.log_append.emit('开始合并...')
        self.fts.chdir(self.fd)
        ffmpeg = self.fts.join(self.workpath, 'ffmpeg')
        fname = self.fts.join(self.fd, self.fts.ganerate_random(16, 5) + '.mp4')
        if self.audio is not None:
            cmd1 = f'{ffmpeg} -y -i old_video.mp4 -i audio.mp3 -c:v copy -c:a aac -strict experimental {fname}'
            cmd2 = r'rm old_video.mp4 audio.mp3'
            bsubprocess(cmd1)
            bsubprocess(cmd2)
        else:
            cmd1 = f'mv old_video.mp4 {fname}.mp4'
            bsubprocess(cmd1)
        self.fts.chdir(self.workpath)
        self.logger.info('视频下载成功!')
        self.ms.log_append.emit(f'视频下载成功!\n文件保存在{fname}')
        self.ui.button_download.setEnabled(False)

    def change_resolution(self):
        """
        切换分辨率时候触发
        """

        resolution = self.ui.combobox_resolution.currentText()
        if resolution == '1080P 高清' or '1080P 60帧':
            quality = 80
        if resolution == '720P 高清' or '720P 60帧':
            quality = 64
        if resolution == '480P 清晰':
            quality = 32
        if resolution == '360P 流畅':
            quality = 16
        try:
            self.urls['audio'] = self.video_data.get('dash').get('audio')[0].get('baseUrl')
        except TypeError as e:
            self.audio = None
            self.ms.log_append.emit('该视频没有音频!')
        self.urls['video'] = list(filter(lambda x: x.get('id') == quality, self.video_data.get('dash').get('video')))[
            0].get(
            'baseUrl')
        # 设置下载按钮是否禁用
        self.ui.button_download.setEnabled(True)

    def update_resolution_ui(self, support_formats):
        """
        获取到视频支持的分辨率之后,更新到UI
        """
        self.ui.combobox_resolution.clear()
        self.ui.label_video_title.setText(self.video_title)
        support_formats = filter(lambda x: x.get('quality') != 116, support_formats)
        for support_format in support_formats:
            self.ui.combobox_resolution.addItem(support_format.get('new_description'))
        else:
            self.ms.log_append.emit('解析成功!')
            # 设置下载按钮是否禁用
            self.ui.button_download.setEnabled(True)
            self.ui.combobox_resolution.repaint()

    def log_append(self, text):
        """
        日志追加到UI上
        """
        self.ui.textbrower_log.append(text)
        self.ui.textbrower_log.reload()
        pass
